import * as Cesium from '@cesiumjs';
import * as utils from "../utils";
import CameraUtils from "../camera";
import {
  g3x_defineReactProperty,
  g3x_defineProperty,
  g3x_defineReadonly,
  GUID
} from "@g3x/utils";
import {
  G3xObjBase
} from "@g3xbase"
import {
  defaultViewerOptions,
  defaultViewerDefinition,
  EMPTY_OBJECT
} from "../defaults";
import {
  viewerUtils,
  tilesetUtils,
  layersUtils,
  imageLayerUtils
} from "../../../viewerUtils";
import {
  utils as globeUtils
} from "../../../globe";
import {
  autorun,
  reaction,
  intercept,
  observable,
  extendObservable,
  computed
} from 'mobx';
import Context from "./Context"

import g3xExtends from "./extends";
import initSchema from "./schema";
import ViewerShortcutAction from "./ViewerShortcutAction";

/* 377 */
/***/
class G3vViewer extends G3xObjBase {
  /**
   * @param {Object} dom
   * @param {Object} viewerOptions viewers Options
   */
  constructor(viewerOptions, g3v) {

    super();

    console.log("G3vViewer constructor!")

    const {
      dom
    } = viewerOptions
    if (!dom) {
      console.error("dom is required!")
    }

    let _this = this;

    utils.verifyViewerOptions(viewerOptions)

    const viewer = utils.createViewer(dom, viewerOptions);
    const scene = viewer.scene;
    const globe = scene.globe;

    _this._viewer = viewer;
    _this.disposers.push(function() {
      return _this._viewer.destroy();
    });

    // 用来监测变量创建和销毁的事件
    _this.initObjectOpsEvent();

    _this._scene = viewer.scene;
    window.xbsj_hpr_scene = _this._scene; // 用于hpr这个函数。。。 很hack的写法。。

    g3x_defineReadonly(this, "viewerOptions", viewerOptions);
    g3x_defineReadonly(this, "guid", viewerOptions.guid);
    g3x_defineReadonly(this, "name", viewerOptions.name);
    g3x_defineProperty(this, "title", viewerOptions.title);
    g3x_defineReadonly(this, "viewer", viewer);
    g3x_defineReadonly(this, "scene", scene);
    g3x_defineReadonly(this, "globe", globe);
    g3x_defineReadonly(this, "dataSources", () => viewer.dataSources);
    g3x_defineReadonly(this, "baseImageLayer", () => viewer.imageryLayers.get(0));
    g3x_defineReadonly(this, "imageryLayers", () => viewer.imageryLayers);
    g3x_defineReadonly(this, "entities", () => viewer.entities);
    g3x_defineReadonly(this, "primitives", () => scene.primitives);
    g3x_defineReadonly(this, "groundPrimitives", () => scene.groundPrimitives);
    g3x_defineReadonly(this, "camera", () => viewer.camera);

    Object.defineProperty(_this, "layers", {
      get() {
        return new function() {
          this.get = (name) => {
            return layersUtils.get(viewer, name)
          }
        }
      }
    })

    _this._context = new Context(_this);
    g3x_defineReadonly(this, "context", () => _this._context);

    _this.navigation = viewerUtils.initNavigation(viewer, viewerOptions.navigation)

    imageLayerUtils.updateImageLayerByOptions(this.baseImageLayer, viewerOptions.viewer.imagery)
    imageLayerUtils.updateImageLayerTitle(this.baseImageLayer, viewerOptions.viewer.imagery)

    viewerUtils.addlayers(viewer, viewerOptions.layers || []);
    globeUtils.updateGlobeByOptions(globe, viewerOptions.globe);

    if (viewerOptions.hideLayers) {
      imageryLayers._layers.forEach(e => e.show = false);
    }

    _this.viewerShortcutAction = new ViewerShortcutAction(_this.viewer);
    _this.viewerShortcutAction.enableShortcut(!!_this.viewerOptions.shortcutAction);

    g3x_defineReactProperty(_this, "shortcutAction", _this.viewerOptions.shortcutAction, (val)=>{
      return _this.viewerShortcutAction.enableShortcut(val);
    }, null)
    // _this.disposers.push(reaction(() => {return _this.shortcutAction},(val) => {
    //   _this.viewerShortcutAction.enableShortcut(val);
    // }));
    _this.disposers.push(() => {
      _this.viewerShortcutAction.destroy();
    });

    viewer.bottomContainer.style.display = (viewerOptions.bottomContainer ? "block" : "none");
  }

  initObjectOpsEvent() {
    let _this = this;
    _this._xbsjObjectOpsEvent = new Cesium.Event();

    extendObservable(_this, {
      _xbsjObjectsMap: observable.map(),
      get flattenedPolygonCollection() {
        return this.getAllObjects('FlattenedPolygonCollection');
      },
      get tilesetCollection() {
        return this.getAllObjects('Tileset');
      },
      get clippingPlaneCollection() {
        return this.getAllObjects('ClippingPlane');
      },
      get pathCollection() {
        return this.getAllObjects('Path');
      }
    }, {
      flattenedPolygonCollection: computed,
      tilesetCollection: computed,
      clippingPlaneCollection: computed,
      pathCollection: computed
    });

    _this.disposers.push(function() {
      // 清理_xbsjObjectsMap
      if (_this._xbsjObjectsMap.size !== 0) {
        const values = _this._xbsjObjectsMap.values()
        var objects = [...values];
        console.log('\u5171\u8BA1\u6709' + objects.length +
          '\u4E2A\u5BF9\u8C61\u672A\u88AB\u6E05\u7406\uFF01\u5206\u522B\u662F\uFF1A');
        objects.forEach(function(obj) {
          return 'guid: ' + obj.name + ' $name\uFF1A' + obj.guid;
        });
        console.log('这些对象将被自动清理掉！');
        objects.forEach(function(obj) {
          return obj.destroy();
        });
      } else {
        console.log('所有对象都已清理！');
      }
      if (_this._xbsjObjectsMap.size !== 0) {
        console.error('仍有对象未清理！');
      }
    });
  }

  getLayer(name) {
    return layersUtils.get(this.viewer, name)
  }
  
  hideAllLayers(){
    this.imageryLayers._layers.forEach(e => e.show = false);
  }

  addTileset(lyrDefine, readyCallback) {
    return tilesetUtils.add(this.viewer, lyrDefine, readyCallback);
  }

  destroy() {
    const {
      entities
    } = this;
    entities.removeAll();
    this.navigation && this.navigation.destroy()
    this.navigation = null;
    this.viewer && this.viewer.destroy()
  }
}

(0, g3xExtends)(G3vViewer);
(0, initSchema)(G3vViewer);

export default G3vViewer;
